package hotnet.filter;

import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.CopyOnWriteArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DefaultIoFilterChainBuilder implements IoFilterChainBuilder {
	private final List<IoFilter> entries = new CopyOnWriteArrayList<IoFilter>();

	private final static Logger LOGGER = LoggerFactory.getLogger(DefaultIoFilterChainBuilder.class);

    public DefaultIoFilterChainBuilder() {
	}

	private boolean contain(String name) {
        return (getFilter(name) != null);
	}

	private void register(int index, IoFilter filter) {
    	if (contain(filter.getName())) {
    		throw new IllegalArgumentException("has the same filter name: " + filter.getName());
		}

    	entries.add(index, filter);
	}

	public final void addFirst(IoFilter filter) {
		register(0, filter);
	}

	public final void addLast(IoFilter filter) {
        register(entries.size(), filter);
	}

	public IoFilter getFilter(String name) {
		for (ListIterator<IoFilter> i = entries.listIterator(); i.hasNext();) {
			IoFilter filter = i.next();

			if (filter.getName().equals(name)) {
				return filter;
			}
		}

		return null;
	}

	public final synchronized void addBefore(String baseName, IoFilter filter) {
		IoFilter baseFilter = getFilter(baseName);

		if (baseFilter == null) {
			throw new IllegalArgumentException("base filter cannot be null");
		}

		for (ListIterator<IoFilter> i = entries.listIterator(); i.hasNext();) {
			IoFilter e = i.next();

			if (e.getName().equals(baseName)) {
				register(i.previousIndex(), filter);
			}
		}

	}

	public final synchronized void addAfter(String baseName, IoFilter filter) {
		IoFilter baseFilter = getFilter(baseName);
		if (baseFilter == null) {
			throw new IllegalArgumentException("base filter cannot be null");
		}

		for (ListIterator<IoFilter> i = entries.listIterator(); i.hasNext();) {
			IoFilter e = i.next();

			if (e.getName().equals(baseName)) {
				register(i.nextIndex(), filter);

				break;
			}
		}

	}

	/**
	 *
	 * @param name
	 * @param newFilter
	 * @return oldFilter
	 */
	public final synchronized IoFilter replace(String name, IoFilter newFilter) {
		IoFilter oldFilter = null;

		for (int i = 0; i < entries.size(); i++) {
			oldFilter = entries.get(i);

			if (oldFilter.equals(name)) {
				entries.set(i, newFilter);

				break;
			}
		}
		
		return oldFilter;
	}

	public final synchronized IoFilter remove(String name) {
		IoFilter oldFilter = null;

		for (ListIterator<IoFilter> i = entries.listIterator(); i.hasNext();) {
			IoFilter filter = i.next();

			if (filter.getName().equals(name)) {
				oldFilter = filter;
				i.remove();

				break;
			}
		}

		return oldFilter;
	}

	public void clear() throws Exception {
		this.entries.clear();
	}

	@Override
	public void buildFilterChain(IoFilterChain chain) {
		for (IoFilter filter : entries) {
			chain.addLast(filter);
		}
	}
    
	@Override
	public String toString() {
		StringBuffer builder = new StringBuffer();
		
		builder.append("filters:{");

		for (int i = 0; i < entries.size(); i++) {
			if (i != 0)
				builder.append(",");
			
			builder.append("(");
			builder.append(entries.get(i).getName());
			builder.append(":");
			builder.append(entries.get(i).getClass().getCanonicalName());
			builder.append(")");
		}
		builder.append("}");
		
		return builder.toString();
	}
}
